package org.jsets.fastboot.security.authc;

import javax.servlet.http.HttpServletRequest;
import org.jsets.fastboot.security.SecurityContext;
import org.jsets.fastboot.security.SecurityUtils;
import org.jsets.fastboot.security.captcha.CaptchaValidateResult;
import org.jsets.fastboot.security.exception.CaptchaVerificationException;
import org.jsets.fastboot.security.token.TokenStub;
import org.jsets.fastboot.util.StringUtils;
import org.jsets.fastboot.util.WebUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AuthenticatorImpl implements IAuthenticator {

	protected void validateCaptcha(AuthcRequest authcRequest) {
		if (StringUtils.isEmpty(authcRequest.getCaptchaKey())) {
			SecurityUtils.getListenerManager().onLoginFailure(authcRequest, "验证码KEY为空");
			throw new CaptchaVerificationException(SecurityUtils.getProperties().getCaptchaKeyBlankTips());
		}
		
		if (StringUtils.isEmpty(authcRequest.getCaptcha())) {
			SecurityUtils.getListenerManager().onLoginFailure(authcRequest, "验证码为空");
			throw new CaptchaVerificationException(SecurityUtils.getProperties().getCaptchaBlankTips());
		}
		
		CaptchaValidateResult result = SecurityUtils.getCaptchaProvider().validateCaptcha(authcRequest.getCaptchaKey(), authcRequest.getCaptcha());
		if(CaptchaValidateResult.INVALID == result) {
			throw new CaptchaVerificationException(SecurityUtils.getProperties().getCaptchaInvalidTips());
		}
		
		if(CaptchaValidateResult.TIMEOUT == result) {
			throw new CaptchaVerificationException(SecurityUtils.getProperties().getCaptchaTimeoutTips());
		}
	}
	
	public AuthcResult login(AuthcRequest authcRequest) throws AuthenticationException {
		if (authcRequest.isCaptchaEnable()) {
			this.validateCaptcha(authcRequest);
		}

		ILoginHandler loginHandler = SecurityUtils.getLoginHandlerManager().getLoginHandler(authcRequest.getAuthType());
		loginHandler.doLogin(authcRequest);
		
		AuthcResult result = SecurityUtils.getTokenManager().issueAccessToken(authcRequest);
		SecurityUtils.getListenerManager().onLoginSuccess(authcRequest, result);
		return result;
	}

	@Override
	public void logout(HttpServletRequest request) {
		String token = WebUtils.getAuthorization(request);
		if (StringUtils.notEmpty(token)) {
			try {
				TokenStub stub = SecurityUtils.validateJWT(token);
				SecurityUtils.getTokenManager().removeTokenStub(stub.getId());
				SecurityContext.cleanup();
				SecurityUtils.getListenerManager().onLogout(stub.getId());
				log.info("用户[{}]登出", stub.getUsername());
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
		}
	}
	
	@Override
	public void authenticate(String token) throws AuthenticationException {
		TokenStub stub = SecurityUtils.getTokenManager().validateAccessToken(token);
		AuthInfo authInfo = new AuthInfo();
		authInfo.setUsername(stub.getUsername());
		authInfo.setAccessToken(token);
		authInfo.setAccessTokenId(stub.getId());
		authInfo.setAccessTokenType(stub.getType());
		SecurityContext.set(authInfo);
		
		UserDetails userDetails = SecurityUtils.getUserInfoProvider().loadUserByUsername(stub.getType(), stub.getUsername());
		if (null == userDetails) {
			SecurityContext.cleanup();
			throw new UsernameNotFoundException(SecurityUtils.getProperties().getUsernameOrPasswdErrorTips());
		}

		if (!userDetails.isAccountNonLocked()) {
			SecurityContext.cleanup();
			throw new UsernameNotFoundException(SecurityUtils.getProperties().getUsernameLockedTips());
		}
	}
	
}